home *** CD-ROM | disk | FTP | other *** search
/ Hottest 6 / Hottest 6 (1996)(PDSoft)[!].iso / software / videoutils / h-m / mandelsquare / mandelsquare-1.06.lha / ILBM.c < prev    next >
C/C++ Source or Header  |  1992-12-20  |  18KB  |  836 lines

  1. /*
  2. **    MandelSquare - AmigaDOS 2.0/3.0 Mandelbrot set explorer
  3. **
  4. **    ILBM.c, Routines to load and save IFF-ILBM files
  5. **
  6. **    Copyright © 1991-1992 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10.     /* A picture handle. */
  11.  
  12. struct PictureInfo
  13. {
  14.     BitMapHeader        BitMapHeader;
  15.     MandelHeader        MandelHeader;
  16.     struct Palette *    Palette;    
  17.     ULONG            ViewModes;
  18.     struct BitMap *        BitMap;
  19. };
  20.  
  21.     /* Global flag. */
  22.  
  23. extern BYTE        Is39;
  24.  
  25.     /* In Packer.c */
  26.  
  27. extern LONG __regargs    PackRow(BYTE **pSource,BYTE *dest,LONG rowSize);
  28. extern VOID __regargs    UnPackRow(BYTE **pSource,BYTE **pDest,WORD dstBytes);
  29.  
  30.     /* In Palette.c */
  31.  
  32. extern VOID        FreePalette(struct Palette *Palette);
  33. extern struct Palette *    AllocPalette(LONG NumColours,BYTE TrueColour);
  34. extern struct Palette *    GetPalette(struct Screen *Screen,struct Palette *Palette);
  35. extern VOID        LoadPalette(struct Screen *Screen,struct Palette *Palette,LONG NumColours);
  36. extern LONG        GetPaletteSize(struct Palette *Palette);
  37. extern BYTE        GetPaletteTriplet(struct Palette *Palette,UBYTE *Triplet,LONG Index);
  38. extern BYTE        SetPaletteTriplet(struct Palette *Palette,UBYTE R,UBYTE G,UBYTE B,LONG Index);
  39. extern ULONG        GetPaletteEntry(struct Palette *Palette,LONG Index);
  40. extern BYTE        SetPaletteEntry(struct Palette *Palette,ULONG Entry,LONG Index);
  41.  
  42.     /* Local, static routines. */
  43.  
  44. STATIC VOID __regargs    GetBody(struct BitMap *BitMap,APTR Body);
  45. STATIC BYTE __regargs    GetColourMap(struct PictureInfo *Info,UBYTE *Palette,LONG Size);
  46. STATIC BYTE __regargs    PutMandel(struct IFFHandle *Handle,MandelHeader *Mandel);
  47. STATIC BYTE __regargs    PutCRange(struct IFFHandle *Handle,CRange *Range);
  48.  
  49.     /* Exported routines. */
  50.  
  51. VOID            FreeCustomBitMap(struct BitMap *BitMap,BYTE Standard);
  52. struct BitMap *        AllocCustomBitMap(UWORD Depth,UWORD Width,UWORD Height,BYTE Standard);
  53. BYTE            PutBitMap(struct IFFHandle *Handle,struct BitMap *BitMap);
  54. BYTE            PutViewModes(struct IFFHandle *Handle,struct ViewPort *VPort);
  55. BYTE            PutColourMap(struct IFFHandle *Handle,struct ViewPort *VPort);
  56. BYTE            PutBitMapHeader(struct IFFHandle *Handle,struct Screen *Screen);
  57. VOID            FreePicture(struct PictureInfo *Info);
  58. struct PictureInfo *    LoadPicture(STRPTR Name);
  59. BYTE            SavePicture(STRPTR Name,struct Screen *Screen,MandelHeader *Mandel);
  60.  
  61.     /* GetBody(struct BitMap *BitMap,APTR Body):
  62.      *
  63.      *    Unpack compressed data.
  64.      */
  65.  
  66. STATIC VOID __regargs
  67. GetBody(struct BitMap *BitMap,APTR Body)
  68. {
  69.     PLANEPTR     Planes[8];
  70.     BYTE        *Source;
  71.     LONG         i,j;
  72.  
  73.         /* Get the source data pointer, we will modify it. */
  74.  
  75.     Source = (BYTE *)Body;
  76.  
  77.         /* Copy the bitplane pointers. */
  78.  
  79.     for(i = 0 ; i < BitMap -> Depth ; i++)
  80.         Planes[i] = BitMap -> Planes[i];
  81.  
  82.         /* CmpByteRun decompression. */
  83.  
  84.     for(i = 0 ; i < BitMap -> Rows ; i++)
  85.     {
  86.         for(j = 0 ; j < BitMap -> Depth ; j++)
  87.             UnPackRow(&Source,&Planes[j],BitMap -> BytesPerRow);
  88.     }
  89. }
  90.  
  91.     /* GetColourMap(struct PictureInfo *Info,UBYTE *Palette,LONG Size):
  92.      *
  93.      *    Fill in colour map information.
  94.      */
  95.  
  96. STATIC BYTE __regargs
  97. GetColourMap(struct PictureInfo *Info,UBYTE *Palette,LONG Size)
  98. {
  99.         /* Get the number of colours. */
  100.  
  101.     LONG NumColours = Size / 3;
  102.  
  103.         /* Allocate palette information. */
  104.  
  105.     if(Info -> Palette = AllocPalette(NumColours,NumColours == 256))
  106.     {
  107.         UWORD    R,G,B;
  108.         LONG    i;
  109.  
  110.             /* Set the 8 bit triplets. */
  111.  
  112.         if(NumColours == 256)
  113.         {
  114.             for(i = 0 ; i < NumColours ; i++)
  115.             {
  116.                 R = *Palette++;
  117.                 G = *Palette++;
  118.                 B = *Palette++;
  119.  
  120.                 SetPaletteTriplet(Info -> Palette,R,G,B,i);
  121.             }
  122.         }
  123.         else
  124.         {
  125.                 /* Set the 4 bit triplets. */
  126.  
  127.             for(i = 0 ; i < NumColours ; i++)
  128.             {
  129.                 R = ((*Palette++) >> 4) & 0xF;
  130.                 G = ((*Palette++) >> 4) & 0xF;
  131.                 B = ((*Palette++) >> 4) & 0xF;
  132.  
  133.                 SetPaletteTriplet(Info -> Palette,R,G,B,i);
  134.             }
  135.         }
  136.  
  137.         return(TRUE);
  138.     }
  139.     else
  140.         return(FALSE);
  141. }
  142.  
  143.     /* PutMandel(struct IFFHandle *Handle,MandelHeader *Mandel):
  144.      *
  145.      *    Save the mandelbrot information chunk.
  146.      */
  147.  
  148. STATIC BYTE __regargs
  149. PutMandel(struct IFFHandle *Handle,MandelHeader *Mandel)
  150. {
  151.     if(!PushChunk(Handle,0,ID_MAND,sizeof(MandelHeader)))
  152.     {
  153.         if(WriteChunkRecords(Handle,Mandel,sizeof(MandelHeader),1) == 1)
  154.         {
  155.             if(!PopChunk(Handle))
  156.                 return(TRUE);
  157.         }
  158.     }
  159.  
  160.     return(FALSE);
  161. }
  162.  
  163.     /* PutCRange(struct IFFHandle *Handle,CRange *Range):
  164.      *
  165.      *    Save the colour cycling chunk.
  166.      */
  167.  
  168. STATIC BYTE __regargs
  169. PutCRange(struct IFFHandle *Handle,CRange *Range)
  170. {
  171.     if(!PushChunk(Handle,0,ID_CRNG,sizeof(CRange)))
  172.     {
  173.         if(WriteChunkRecords(Handle,Range,sizeof(CRange),1) == 1)
  174.         {
  175.             if(!PopChunk(Handle))
  176.                 return(TRUE);
  177.         }
  178.     }
  179.  
  180.     return(FALSE);
  181. }
  182.  
  183.     /* FreeCustomBitMap(struct BitMap *BitMap,BYTE Standard):
  184.      *
  185.      *    Free bitmap memory.
  186.      */
  187.  
  188. VOID
  189. FreeCustomBitMap(struct BitMap *BitMap,BYTE Standard)
  190. {
  191.     if(Is39)
  192.         FreeBitMap(BitMap);
  193.     else
  194.     {
  195.         if(BitMap)
  196.         {
  197.             WORD i;
  198.  
  199.             for(i = 0 ; i < BitMap -> Depth ; i++)
  200.             {
  201.                 if(BitMap -> Planes[i])
  202.                     FreeVec(BitMap -> Planes[i]);
  203.             }
  204.  
  205.             FreeVec(BitMap);
  206.         }
  207.     }
  208. }
  209.  
  210.     /* AllocCustomBitMap(UWORD Depth,UWORD Width,UWORD Height,BYTE Standard):
  211.      *
  212.      *    Allocate bitmap memory.
  213.      */
  214.  
  215. struct BitMap *
  216. AllocCustomBitMap(UWORD Depth,UWORD Width,UWORD Height,BYTE Standard)
  217. {
  218.     if(Is39)
  219.     {
  220.         extern struct Screen *Screen;
  221.  
  222.             /* Note: `Standard' assumes that a BitMap with properly
  223.              *       set line modulo values (i.e. no chunky, interleaved
  224.              *       or whatever layout possible) will be allocated and
  225.              *       returned. This BitMap will never be used for
  226.              *       screen display but rather as a temporary buffer
  227.              *       for image compression.
  228.              */
  229.  
  230.         if(Standard)
  231.             return(AllocBitMap(Width,Height,Depth,BMF_CLEAR,NULL));
  232.         else
  233.             return(AllocBitMap(Width,Height,Depth,BMF_CLEAR | BMF_DISPLAYABLE,Screen -> RastPort . BitMap));
  234.     }
  235.     else
  236.     {
  237.         struct BitMap *BitMap;
  238.  
  239.             /* Allocate the bitmap body. */
  240.  
  241.         if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY | MEMF_CLEAR))
  242.         {
  243.             BYTE    Success = TRUE;
  244.             LONG    PlaneSize,
  245.                 i;
  246.  
  247.                 /* Initialize the bitmap. */
  248.  
  249.             InitBitMap(BitMap,Depth,Width,Height);
  250.  
  251.                 /* Get the plane size. */
  252.  
  253.             PlaneSize = BitMap -> BytesPerRow * BitMap -> Rows;
  254.  
  255.                 /* Allocate the single bitplanes. */
  256.  
  257.             for(i = 0 ; Success && i < Depth ; i++)
  258.             {
  259.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PlaneSize,MEMF_CHIP | MEMF_CLEAR)))
  260.                     Success = FALSE;
  261.             }
  262.  
  263.                 /* Return the result. */
  264.  
  265.             if(Success)
  266.                 return(BitMap);
  267.             else
  268.                 FreeCustomBitMap(BitMap,Standard);
  269.         }
  270.     }
  271.  
  272.     return(NULL);
  273. }
  274.  
  275.     /* PutBitMap(struct IFFHandle *Handle,struct BitMap *BitMap):
  276.      *
  277.      *    Save a bitmap to disk.
  278.      */
  279.  
  280. BYTE
  281. PutBitMap(struct IFFHandle *Handle,struct BitMap *BitMap)
  282. {
  283.     PLANEPTR    *Planes;
  284.     BYTE        *PackBuffer,
  285.              Success = FALSE;
  286.     LONG         PackedBytes,
  287.              i,j;
  288.  
  289.         /* Allocate the bitplane information. */
  290.  
  291.     if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
  292.     {
  293.             /* Allocate the compression buffer. */
  294.  
  295.         if(PackBuffer = (BYTE *)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
  296.         {
  297.                 /* Copy the planes over. */
  298.  
  299.             for(i = 0 ; i < BitMap -> Depth ; i++)
  300.                 Planes[i] = BitMap -> Planes[i];
  301.  
  302.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  303.             {
  304.                 Success = TRUE;
  305.  
  306.                     /* Run down the rows. */
  307.  
  308.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  309.                 {
  310.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  311.                     {
  312.                             /* Pack the data. */
  313.  
  314.                         PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  315.  
  316.                             /* Write it to disk. */
  317.  
  318.                         if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
  319.                             Success = FALSE;
  320.                     }
  321.                 }
  322.  
  323.                 if(PopChunk(Handle))
  324.                     Success = FALSE;
  325.             }
  326.  
  327.             FreeVec(PackBuffer);
  328.         }
  329.  
  330.         FreeVec(Planes);
  331.     }
  332.  
  333.     return(Success);
  334. }
  335.  
  336.     /* PutViewModes(struct IFFHandle *Handle,struct ViewPort *VPort):
  337.      *
  338.      *    Save the display modes to disk.
  339.      */
  340.  
  341. BYTE
  342. PutViewModes(struct IFFHandle *Handle,struct ViewPort *VPort)
  343. {
  344.     ULONG ViewModes = GetVPModeID(VPort);
  345.  
  346.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  347.     {
  348.         if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
  349.         {
  350.             if(!PopChunk(Handle))
  351.                 return(TRUE);
  352.         }
  353.     }
  354.  
  355.     return(FALSE);
  356. }
  357.  
  358.     /* PutColourMap(struct IFFHandle *Handle,struct ViewPort *VPort):
  359.      *
  360.      *    Save the colour map to disk.
  361.      */
  362.  
  363. BYTE
  364. PutColourMap(struct IFFHandle *Handle,struct ViewPort *VPort)
  365. {
  366.     ColorRegister     Colour;
  367.     LONG         i;
  368.  
  369.     if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
  370.     {
  371.             /* Eight or four bit triplets? */
  372.  
  373.         if(VPort -> ColorMap -> Count == 256)
  374.         {
  375.             ULONG Triplet[3];
  376.  
  377.                 /* Run down the colour map... */
  378.  
  379.             for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
  380.             {
  381.                     /* Get the colour information, returned
  382.                      * as three 32 bit quantities.
  383.                      */
  384.  
  385.                 GetRGB32(VPort -> ColorMap,i,1,Triplet);
  386.  
  387.                     /* As of this writing, only eight
  388.                      * bit quantities are supported for
  389.                      * CMAP chunks.
  390.                      */
  391.  
  392.                 Colour . red    = Triplet[0] >> 24;
  393.                 Colour . green    = Triplet[1] >> 24;
  394.                 Colour . blue    = Triplet[2] >> 24;
  395.  
  396.                     /* Write the data. */
  397.  
  398.                 if(WriteChunkRecords(Handle,&Colour,3,1) != 1)
  399.                     return(FALSE);
  400.             }
  401.         }
  402.         else
  403.         {
  404.             ULONG    Value,
  405.                 R,G,B;
  406.  
  407.                 /* Run down the colour map... */
  408.  
  409.             for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
  410.             {
  411.                     /* Get the colour map entry. */
  412.  
  413.                 Value = GetRGB4(VPort -> ColorMap,i);
  414.  
  415.                     /* Split the colour information. */
  416.  
  417.                 R = (Value >> 8) & 0xF;
  418.                 G = (Value >> 4) & 0xF;
  419.                 B = (Value     ) & 0xF;
  420.  
  421.                     /* Fill it in. */
  422.  
  423.                 Colour . red    = (R << 4) | R;
  424.                 Colour . green    = (G << 4) | G;
  425.                 Colour . blue    = (B << 4) | B;
  426.  
  427.                     /* Write the data. */
  428.  
  429.                 if(WriteChunkRecords(Handle,&Colour,3,1) != 1)
  430.                     return(FALSE);
  431.             }
  432.         }
  433.  
  434.         if(!PopChunk(Handle))
  435.             return(TRUE);
  436.     }
  437.  
  438.     return(FALSE);
  439. }
  440.  
  441.     /* PutBitMapHeader(struct IFFHandle *Handle,struct Screen *Screen):
  442.      *
  443.      *    Save the bitmap header to disk.
  444.      */
  445.  
  446. BYTE
  447. PutBitMapHeader(struct IFFHandle *Handle,struct Screen *Screen)
  448. {
  449.     BitMapHeader        Header;
  450.     struct DisplayInfo    DisplayInfo;
  451.  
  452.         /* Fill in the standard data. */
  453.  
  454.     Header . w            = Screen -> Width;
  455.     Header . h            = Screen -> Height;
  456.     Header . pageWidth        = Screen -> Width;
  457.     Header . pageHeight        = Screen -> Height;
  458.     Header . x            = 0;
  459.     Header . y            = 0;
  460.     Header . nPlanes        = Screen -> RastPort . BitMap -> Depth;
  461.     Header . masking        = 0;
  462.     Header . compression        = 1;
  463.     Header . pad1            = 0;
  464.     Header . transparentColor    = 0;
  465.  
  466.         /* Get the aspect ration information. */
  467.  
  468.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,GetVPModeID(&Screen -> ViewPort)))
  469.     {
  470.             /* Fill it in. */
  471.  
  472.         Header . xAspect = DisplayInfo . Resolution . x;
  473.         Header . yAspect = DisplayInfo . Resolution . y;
  474.  
  475.             /* Write the data. */
  476.  
  477.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
  478.         {
  479.             if(WriteChunkRecords(Handle,&Header,sizeof(BitMapHeader),1) == 1)
  480.             {
  481.                 if(!PopChunk(Handle))
  482.                     return(TRUE);
  483.             }
  484.         }
  485.     }
  486.  
  487.     return(FALSE);
  488. }
  489.  
  490.     /* FreePicture(struct PictureInfo *Info):
  491.      *
  492.      *    Free picture information.
  493.      */
  494.  
  495. VOID
  496. FreePicture(struct PictureInfo *Info)
  497. {
  498.     if(Info)
  499.     {
  500.             /* Free the bitmap. */
  501.  
  502.         if(Info -> BitMap)
  503.             FreeCustomBitMap(Info -> BitMap,TRUE);
  504.  
  505.             /* Free the palette. */
  506.  
  507.         if(Info -> Palette)
  508.             FreePalette(Info -> Palette);
  509.  
  510.             /* Free the information buffer. */
  511.  
  512.         FreeVec(Info);
  513.     }
  514. }
  515.  
  516.     /* LoadPicture(STRPTR Name):
  517.      *
  518.      *    Load an IFF-ILBM image file.
  519.      */
  520.  
  521. struct PictureInfo *
  522. LoadPicture(STRPTR Name)
  523. {
  524.         /* The information we wil pick up on the fly. */
  525.  
  526.     STATIC ULONG Properties[2 * 4] =
  527.     {
  528.         ID_ILBM,ID_BMHD,
  529.         ID_ILBM,ID_CAMG,
  530.         ID_ILBM,ID_CMAP,
  531.         ID_ILBM,ID_MAND
  532.     };
  533.  
  534.     struct PictureInfo *Info;
  535.  
  536.         /* Allocate the information buffer. */
  537.  
  538.     if(Info = (struct PictureInfo *)AllocVec(sizeof(struct PictureInfo),MEMF_ANY | MEMF_CLEAR))
  539.     {
  540.         struct IFFHandle    *Handle;
  541.         BYTE             Success = FALSE;
  542.  
  543.             /* Allocate iff handle. */
  544.  
  545.         if(Handle = AllocIFF())
  546.         {
  547.                 /* Open file for reading. */
  548.  
  549.             if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  550.             {
  551.                     /* Make it known as a DOS file. */
  552.  
  553.                 InitIFFasDOS(Handle);
  554.  
  555.                 if(!OpenIFF(Handle,IFFF_READ))
  556.                 {
  557.                         /* Remember the properties to store. */
  558.  
  559.                     if(!PropChunks(Handle,Properties,4))
  560.                     {
  561.                             /* Stop at the BODY chunk. */
  562.  
  563.                         if(!StopChunk(Handle,ID_ILBM,ID_BODY))
  564.                         {
  565.                             struct StoredProperty *Prop;
  566.  
  567.                                 /* Scan for it... */
  568.  
  569.                             if(!ParseIFF(Handle,IFFPARSE_SCAN))
  570.                             {
  571.                                 Success = TRUE;
  572.  
  573.                                     /* Try to find the bitmap header. */
  574.  
  575.                                 if(Prop = FindProp(Handle,ID_ILBM,ID_BMHD))
  576.                                 {
  577.                                     CopyMem(Prop -> sp_Data,&Info -> BitMapHeader,sizeof(BitMapHeader));
  578.  
  579.                                         /* No weird data, please. */
  580.  
  581.                                     if(Info -> BitMapHeader . nPlanes < 1 || Info -> BitMapHeader . nPlanes > 8 || Info -> BitMapHeader . w != Info -> BitMapHeader . pageWidth || Info -> BitMapHeader . h != Info -> BitMapHeader . pageHeight)
  582.                                         Success = FALSE;
  583.  
  584.                                         /* No masking and CmpByteRun compression, please. */
  585.  
  586.                                     if(Info -> BitMapHeader . masking || Info -> BitMapHeader . compression != 1)
  587.                                         Success = FALSE;
  588.                                 }
  589.                                 else
  590.                                     Success = FALSE;
  591.  
  592.                                     /* Can we continue? */
  593.  
  594.                                 if(Success)
  595.                                 {
  596.                                         /* Check for CAMG chunk... */
  597.  
  598.                                     if(Prop = FindProp(Handle,ID_ILBM,ID_CAMG))
  599.                                     {
  600.                                         Info -> ViewModes = *(ULONG *)Prop -> sp_Data;
  601.  
  602.                                             /* Mask out the old 1.3 bits... */
  603.  
  604.                                         if(!(Info -> ViewModes & MONITOR_ID_MASK) || ((Info -> ViewModes & EXTENDED_MODE) && !(Info -> ViewModes & 0xFFFF0000)))
  605.                                             Info -> ViewModes &= ~(EXTENDED_MODE | SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO);
  606.  
  607.                                             /* Can we get along with it? */
  608.  
  609.                                         if(!(Info -> ViewModes & EXTENDED_MODE) && (Info -> ViewModes & 0xFFFF0000))
  610.                                             Prop = NULL;
  611.                                         else
  612.                                         {
  613.                                                 /* Is the display mode available? */
  614.  
  615.                                             if(ModeNotAvailable(Info -> ViewModes))
  616.                                             {
  617.                                                     /* Mask out the valid bits. */
  618.  
  619.                                                 Info -> ViewModes &= (LACE | HIRES | HAM | EXTRA_HALFBRITE);
  620.  
  621.                                                     /* Any chance? */
  622.  
  623.                                                 if(ModeNotAvailable(Info -> ViewModes))
  624.                                                     Success = FALSE;
  625.                                             }
  626.                                         }
  627.                                     }
  628.  
  629.                                         /* No chance so far, try to make up the
  630.                                          * data from scratch.
  631.                                          */
  632.  
  633.                                     if(!Prop && Success)
  634.                                     {
  635.                                         extern struct GfxBase *GfxBase;
  636.  
  637.                                         Info -> ViewModes = NULL;
  638.  
  639.                                         if(Info -> BitMapHeader . pageHeight > ((GfxBase -> DisplayFlags & PAL) ? 256 : 200))
  640.                                             Info -> ViewModes |= LACE;
  641.  
  642.                                         if(Info -> BitMapHeader . pageWidth >= 640)
  643.                                             Info -> ViewModes |= HIRES;
  644.  
  645.                                         if(Info -> BitMapHeader . nPlanes == 6)
  646.                                             Info -> ViewModes |= HAM;
  647.                                     }
  648.  
  649.                                         /* Try to pick up the colour map. */
  650.  
  651.                                     if(Success)
  652.                                     {
  653.                                         if(Prop = FindProp(Handle,ID_ILBM,ID_CMAP))
  654.                                         {
  655.                                             if(!GetColourMap(Info,(UBYTE *)Prop -> sp_Data,Prop -> sp_Size))
  656.                                                 Success = FALSE;
  657.                                         }
  658.                                     }
  659.  
  660.                                         /* We _need_ the mandelbrot data. */
  661.  
  662.                                     if(Success)
  663.                                     {
  664.                                         if(Prop = FindProp(Handle,ID_ILBM,ID_MAND))
  665.                                             CopyMem(Prop -> sp_Data,&Info -> MandelHeader,sizeof(MandelHeader));
  666.                                         else
  667.                                             Success = FALSE;
  668.                                     }
  669.  
  670.                                         /* Successful so far? */
  671.  
  672.                                     if(Success)
  673.                                     {
  674.                                         struct ContextNode *BodyChunk;
  675.  
  676.                                         Success = FALSE;
  677.  
  678.                                         if(BodyChunk = CurrentChunk(Handle))
  679.                                         {
  680.                                             APTR Body;
  681.  
  682.                                                 /* Allocate space for the body data. */
  683.  
  684.                                             if(Body = AllocVec(BodyChunk -> cn_Size,MEMF_ANY))
  685.                                             {
  686.                                                     /* Read the data. */
  687.  
  688.                                                 if(ReadChunkRecords(Handle,Body,BodyChunk -> cn_Size,1) == 1)
  689.                                                 {
  690.                                                         /* Allocate a suitable bitmap. */
  691.  
  692.                                                     if(Info -> BitMap = AllocCustomBitMap(Info -> BitMapHeader . nPlanes,Info -> BitMapHeader . w,Info -> BitMapHeader . h,TRUE))
  693.                                                     {
  694.                                                             /* Unpack the data. */
  695.  
  696.                                                         GetBody(Info -> BitMap,Body);
  697.  
  698.                                                         Success = TRUE;
  699.                                                     }
  700.                                                 }
  701.  
  702.                                                 FreeVec(Body);
  703.                                             }
  704.                                         }
  705.                                     }
  706.                                 }
  707.                             }
  708.                         }
  709.                     }
  710.  
  711.                     CloseIFF(Handle);
  712.                 }
  713.  
  714.                 Close(Handle -> iff_Stream);
  715.             }
  716.  
  717.             FreeIFF(Handle);
  718.         }
  719.  
  720.         if(!Success)
  721.         {
  722.             FreePicture(Info);
  723.  
  724.             Info = NULL;
  725.         }
  726.     }
  727.  
  728.     return(Info);
  729. }
  730.  
  731.     /* SavePicture(STRPTR Name,struct Screen *Screen,MandelHeader *Mandel):
  732.      *
  733.      *    Save the screen to an IFF-ILBM disk file.
  734.      */
  735.  
  736. BYTE
  737. SavePicture(STRPTR Name,struct Screen *Screen,MandelHeader *Mandel)
  738. {
  739.     struct BitMap     *BitMap;
  740.     BYTE         Success    = FALSE,
  741.              Delete        = FALSE;
  742.  
  743.         /* Allocate local bitmap, don't use the plain screen bitmap. */
  744.  
  745.     if(BitMap = AllocCustomBitMap(Screen -> RastPort . BitMap -> Depth,Screen -> Width,Screen -> Height,TRUE))
  746.     {
  747.         struct IFFHandle *Handle;
  748.  
  749.             /* Copy the screen bitmap. */
  750.  
  751.         BltBitMap(Screen -> RastPort . BitMap,0,0,BitMap,0,0,Screen -> Width,Screen -> Height,0xC0,0xFF,NULL);
  752.  
  753.             /* Do the vanilla setup. */
  754.  
  755.         if(Handle = AllocIFF())
  756.         {
  757.             if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  758.             {
  759.                 Delete = TRUE;
  760.  
  761.                 InitIFFasDOS(Handle);
  762.  
  763.                 if(!OpenIFF(Handle,IFFF_WRITE))
  764.                 {
  765.                     if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  766.                     {
  767.                             /* Put the bitmap header. */
  768.  
  769.                         if(PutBitMapHeader(Handle,Screen))
  770.                         {
  771.                                 /* Put the colour information. */
  772.  
  773.                             if(PutColourMap(Handle,&Screen -> ViewPort))
  774.                             {
  775.                                     /* Put the display modes. */
  776.  
  777.                                 if(PutViewModes(Handle,&Screen -> ViewPort))
  778.                                 {
  779.                                     CRange Range;
  780.  
  781.                                         /* Initialize the colour cycling chunk. */
  782.  
  783.                                     Range . pad1    = 0;
  784.                                     Range . rate    = 16384 / (60 / 20);
  785.                                     Range . flags    = RNG_ACTIVE;
  786.                                     Range . low    = 2;
  787.                                     Range . high    = Screen -> ViewPort . ColorMap -> Count - 1;
  788.  
  789.                                         /* Put the colour cycling chunk. */
  790.  
  791.                                     if(PutCRange(Handle,&Range))
  792.                                     {
  793.                                             /* Put the mandelbrot information chunk. */
  794.  
  795.                                         if(PutMandel(Handle,Mandel))
  796.                                         {
  797.                                                 /* Put the bitmap data. */
  798.  
  799.                                             if(PutBitMap(Handle,BitMap))
  800.                                             {
  801.                                                     /* We're done now. */
  802.  
  803.                                                 if(!PopChunk(Handle))
  804.                                                     Success = TRUE;
  805.                                             }
  806.                                         }
  807.                                     }
  808.                                 }
  809.                             }
  810.                         }
  811.                     }            
  812.  
  813.                     CloseIFF(Handle);
  814.                 }
  815.  
  816.                 if(!Close(Handle -> iff_Stream))
  817.                     Success = FALSE;
  818.             }
  819.  
  820.             FreeIFF(Handle);
  821.         }
  822.  
  823.         FreeCustomBitMap(BitMap,TRUE);
  824.     }
  825.  
  826.     if(Success)
  827.         SetProtection(Name,FIBF_EXECUTE);
  828.     else
  829.     {
  830.         if(Delete)
  831.             DeleteFile(Name);
  832.     }
  833.  
  834.     return(Success);
  835. }
  836.